﻿using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
using System.IO;

namespace Framework.Utils
{
    /// <summary>
    /// 压缩包工具类
    /// </summary>
    public class ZipUtilsc
    {
        public const int BUFFER_SIZE = 2048;
        private static byte[] buffer = new byte[BUFFER_SIZE];

        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="sourceFilePaths">资源文件名称集合</param>
        /// <param name="zipFilePath">资源名称</param>
        /// <param name="compressLevel">压缩等级</param>
        public static void ZipCompressFiles(List<string> sourceFilePaths, string zipFilePath, CompressLevel compressLevel)
        {
            if (File.Exists(zipFilePath))
                File.Delete(zipFilePath);
            FileStream baseOutputStream = File.Create(zipFilePath);
            ZipOutputStream zipOutputStream = new ZipOutputStream(baseOutputStream);
            for (int i = 0; i < sourceFilePaths.Count; i++)
            {
                string filePath = sourceFilePaths[i];
                FileStream fileStream = File.OpenRead(filePath);
                byte[] array = new byte[fileStream.Length];
                fileStream.Read(array, 0, array.Length);
                fileStream.Close();
                ZipEntry entry = new ZipEntry(Path.GetFileName(filePath));
                zipOutputStream.PutNextEntry(entry);
                zipOutputStream.SetLevel(Convert.ToInt32(compressLevel));
                zipOutputStream.Write(array, 0, array.Length);
            }
            zipOutputStream.Finish();
            zipOutputStream.Close();
        }
        /// <summary>
        /// 压缩文件夹
        /// </summary>
        /// <param name="directoryPath">文件夹路径</param>
        /// <param name="zipFilePath">压缩文件路径</param>
        /// <param name="compressLevel">压缩等级</param>
        public static void ZipCompressFolder(string directoryPath, string zipFilePath, CompressLevel compressLevel)
        {
            if (!Directory.Exists(directoryPath))
                return;
            if (File.Exists(zipFilePath))
                File.Delete(zipFilePath);
            ZipOutputStream stream = new ZipOutputStream(File.Create(zipFilePath));
            stream.SetLevel(Convert.ToInt32(compressLevel));
            string[] filenames = Directory.GetFiles(directoryPath, "*.*", SearchOption.AllDirectories);
            foreach (string file in filenames)
            {
                if (Path.GetExtension(file).Equals(".meta")) continue;
                ZipEntry entry = new ZipEntry(file.Replace(directoryPath, "").Replace("\\", "/"));
                entry.DateTime = DateTime.Now;
                stream.PutNextEntry(entry);
                using (FileStream fs = File.OpenRead(file))
                {
                    int sourceBytes;
                    do
                    {
                        sourceBytes = fs.Read(buffer, 0, buffer.Length);
                        stream.Write(buffer, 0, sourceBytes);
                    } while (sourceBytes > 0);
                }
            }
            stream.Finish();
            stream.Close();
        }
        /// <summary>
        /// 解压缩文件
        /// </summary>
        /// <param name="zipFilePath">压缩文件路径</param>
        /// <param name="targetFilePath">解压路径</param>
        public static void ZipDecompressFile(string zipFilePath, string targetFilePath = null)
        {
            string directoryName = targetFilePath;
            if (string.IsNullOrEmpty(targetFilePath))
                directoryName = Path.Combine(Path.GetDirectoryName(zipFilePath), Path.GetFileNameWithoutExtension(zipFilePath)).Replace("\\", "/") + "/";
            if (!Directory.Exists(directoryName))
                Directory.CreateDirectory(directoryName);
            string currentDirectory = directoryName;
            int size = BUFFER_SIZE;
            ZipEntry theEntry = null;
            using (ZipInputStream s = new ZipInputStream(File.OpenRead(zipFilePath)))
            {
                while((theEntry = s.GetNextEntry()) != null)
                {
                    if(!string.IsNullOrEmpty(theEntry.Name))
                    {
                        if(theEntry.Name.Contains("/"))
                        {
                            string path = Path.GetDirectoryName(currentDirectory + theEntry.Name);
                            if (!Directory.Exists(path))
                                Directory.CreateDirectory(path);
                        }
                        string filePath = currentDirectory + theEntry.Name;
                        if (File.Exists(filePath))
                            File.Delete(filePath);
                        using (FileStream streamWriter = File.Create(filePath))
                        {
                            while(true)
                            {
                                size = s.Read(buffer, 0, buffer.Length);
                                if (size <= 0) break;
                                streamWriter.Write(buffer, 0, size);
                            }
                            streamWriter.Close();
                        }
                    }
                }
                s.Close();
            }
        }
    }
    /// <summary>
    /// 0 - store only to 9 - means best compression
    /// </summary>
    public enum CompressLevel
    {
        Store = 0,
        Level1,
        Level2,
        Level3,
        Level4,
        Level5,
        Level6,
        Level7,
        Level8,
        Best
    }
}
